using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using DotNet.Utilities;
using DotNet.Utilities.ConsoleHelper;
using DotNet.Utilities.Sql.SqlSugar;
using PropertyChanged;
using SqlSugar;
using WPFPractice.EntitySugar;
using WPFPractice.Models;
using WPFPractice.Utils;
using WPFPractice.ViewModels;
using WPFTemplateLib.WpfHelpers;

namespace WPFPractice.Windows
{
	public partial class WinDataGrid4 : Window
	{
		private DataGrid4ViewModel _vm;

		public WinDataGrid4()
		{
			InitializeComponent();
			DataContext = _vm = new DataGrid4ViewModel();

			_vm.SelectedItemChanged += OnSelectedItemChanged;
		}

		/// <summary>
		/// 选中项改变事件执行方法
		/// </summary>
		/// <param name="index">选中行索引</param>
		private void OnSelectedItemChanged(int index)
		{
			try
			{
				if(index >= 0)
				{
					Dg.ScrollIntoView(Dg.Items.GetItemAt(index));
				}
			}
			catch(Exception ex)
			{
				MessageBox.Show($"{ex}");
			}
		}

		private void EventSetter_LostFocus(object sender, RoutedEventArgs e)
		{
			var selected = _vm.SelectedItem;
			if(selected != null)
			{
				//selected.EditType = EditTypeEnum.Show;
			}
		}

		private void Dg_OnMouseDown(object sender, MouseButtonEventArgs e)
		{
			switch(sender)
			{
				//只在点击表格其它地方时执行某些操作，点击行时不处理;
				case DataGrid dg:
					//想要进行的操作写这里;

					MessageBox.Show("点击了表格空白处");

					//如果是自动列，使用此方法可以使选中的单元格进入编辑模式，但是不知道如何使整行进入编辑模式;
					dg.BeginEdit();

					break;
				case DataGridRow row:
					e.Handled = true; //标记为已处理，就不会触发之后的 DataGrid 的 MouseDown 事件;
					break;
				default:
					break;
			}
		}
	}
}

namespace WPFPractice.ViewModels
{
	[AddINotifyPropertyChangedInterface]
	public class DataGrid4ViewModel : MyBindableBase
	{
		#region 成员

		/// <summary>
		/// 改变前的对象引用
		/// </summary>
		private User _originUser;

		private SqlSugarHelper _dbHelper;

		#endregion

		#region Bindable

		/// <summary>
		/// 表格数据
		/// </summary>
		public ObservableCollection<User> Datas { get; set; }

		/// <summary>
		/// 选中项改变事件
		/// </summary>
		public event Action<int> SelectedItemChanged;

		private User _SelectedItem;
		/// <summary>
		/// 选中项
		/// </summary>
		public User SelectedItem
		{
			get => _SelectedItem;
			set
			{
				SetProperty(ref _SelectedItem, value);

				SelectedItemChanged?.Invoke(Datas.IndexOf(_SelectedItem));
			}
		}

		private EditTypeEnum _editType = EditTypeEnum.Show;
		/// <summary>
		/// 编辑模式
		/// </summary>
		public EditTypeEnum EditType
		{
			get => _editType;
			set
			{
				_editType = value;
				ShowInfoUc($"切换到 {_editType.GetEnumDescription()}");
			}
		}

		/// <summary>
		/// 数据库连接配置
		/// </summary>
		public DbConnectPara DbConnectPara { get; set; } = new();

		#endregion

		#region Command

		/// <summary>
		/// 切换到新增模式命令
		/// </summary>
		public ICommand EnterAddModeCmd { get; set; }

		/// <summary>
		/// 添加用户命令
		/// </summary>
		public ICommand AddUserCmd { get; set; }

		/// <summary>
		/// 表格选择行变化事件触发命令
		/// </summary>
		public ICommand SelectionChangedCmd { get; set; }

		/// <summary>
		/// 是否能执行选择行变化命令
		/// </summary>
		public bool IsCanSelectionChanged { get; set; } = true;

		/// <summary>
		/// 删除命令
		/// </summary>
		public ICommand DeleteCmd { get; set; }

		/// <summary>
		/// 进入编辑模式命令
		/// </summary>
		public ICommand EnterEditCmd { get; set; }

		/// <summary>
		/// 失去焦点事件命令
		/// </summary>
		public ICommand LostFocusCmd { get; set; }

		/// <summary>
		/// 连接数据库命令
		/// </summary>
		public ICommand ConnectCmd { get; set; }

		/// <summary>
		/// 读取数据命令
		/// </summary>
		public ICommand ReadCmd { get; set; }

		/// <summary>
		/// 更新用户命令
		/// </summary>
		public ICommand UpdateUserCmd { get; set; }

		#endregion

		public DataGrid4ViewModel()
		{
			Console.SetOut(new ConsoleWriter(s =>
			{
				ShowInfoUc(s);
			}));

			SetCommandMethod();

			_ = InitValueAsync();
		}

		/// <summary>
		/// 数据初始化
		/// </summary>
		private async Task InitValueAsync()
		{
			await Task.Delay(1);
			ShowInfoUc("演示 SqlSugar（Sqlite） 增删改查");
		}

		/// <summary>
		/// 命令方法赋值(在构造函数中调用)
		/// </summary>
		private void SetCommandMethod()
		{
			EnterAddModeCmd ??= new RelayCommand(o => true, o =>
			{
				EditType = EditTypeEnum.Add;
				SelectedItem = new User();
			});

			ConnectCmd ??= new RelayCommand(o => true, o =>
			{
				try
				{
					var db = new SqlSugarClient
					(
						new ConnectionConfig()
						{
							ConnectionString = $"datasource={DbConnectPara.DbName}.db",
							DbType = DbType.Sqlite,
							IsAutoCloseConnection = true
						},
						db =>
						{
							db.Aop.OnLogExecuting = (sql, pars) =>
							{
								//获取原生SQL推荐 5.1.4.63  性能OK
								Console.WriteLine(UtilMethods.GetNativeSql(sql, pars));

								//获取无参数化SQL 对性能有影响，特别大的SQL参数多的，调试使用
								//Console.WriteLine(UtilMethods.GetSqlString(DbType.SqlServer,sql,pars))
							};
						}
					);

					_dbHelper = SqlSugarHelper.GetNewHelper(db);
					if (_dbHelper == null)
					{
						Console.WriteLine("创建数据库失败!");
						return;
					}

					//初始化表
					_dbHelper.Db.CodeFirst.InitTables<UserEntity>();

					ToastToScreenCmd.Execute("连接成功");
				}
				catch(Exception ex)
				{
					Console.WriteLine($"连接数据库时异常：{ex}");
				}
			});

			ReadCmd ??= new RelayCommand(o => _dbHelper != null, o =>
			{
				try
				{
					var userEntities = _dbHelper.Find<UserEntity>().ToList();
					if(userEntities.Any())
					{
						var users = userEntities.Select(e => ClassHelper.AutoMap<User, UserEntity>(e)).ToList();
						Datas = new(users);
						ToastToScreenCmd.Execute("读取成功");
					}
					else
					{
						Datas = TestDataHelper.GetUsers();
						var users = Datas.Select(u => ClassHelper.AutoMap<UserEntity, User>(u)).ToList();
						_dbHelper.UpdateOrInsert(users);
						ToastToScreenCmd.Execute("模拟数据写入数据库成功");
					}

					EditType = EditTypeEnum.Show;
				}
				catch(Exception ex)
				{
					Console.WriteLine($"读取数据时异常：{ex}");
				}
			});

			AddUserCmd ??= new RelayCommand(o => !string.IsNullOrEmpty(SelectedItem?.UserName), o =>
			{
				try
				{
					Datas.Add(SelectedItem);
					UserEntity entity = ClassHelper.AutoMap<UserEntity, User>(SelectedItem);
					_dbHelper.UpdateOrInsert(new List<UserEntity> { entity });

					ShowInfoUc($"已添加用户 {SelectedItem.UserName}");

					ReadCmd.Execute(null);
				}
				catch(Exception ex)
				{
					Console.WriteLine($"添加用户时异常：{ex}");
				}
			});

			UpdateUserCmd ??= new RelayCommand(o => !string.IsNullOrEmpty(SelectedItem?.UserName), o =>
			{
				try
				{
					UserEntity entity = ClassHelper.AutoMap<UserEntity, User>(SelectedItem);
					var result = _dbHelper.UpdateOrInsert(new List<UserEntity> { entity });
					if(result.IsSuccess)
					{
						ShowInfoUc($"已更新用户 {SelectedItem.UserName}");
					}
					else
					{
						Console.WriteLine($"更新用户[{SelectedItem.UserName}]时出错：{result.Message}");
					}

					ReadCmd.Execute(null);
				}
				catch(Exception ex)
				{
					Console.WriteLine($"更新用户时异常：{ex}");
				}
			});

			SelectionChangedCmd ??= new RelayCommand(o => IsCanSelectionChanged, o =>
			{
				try
				{
					IsCanSelectionChanged = false;

					var args = o as SelectionChangedEventArgs;
					EditType = EditTypeEnum.Show;

					if(_originUser != null)
					{
						_originUser.EditType = EditTypeEnum.Show;

						//演示属性变动后的业务处理(取消方法);
						_originUser.PropertyChanged -= User_PropertyChanged;
						_originUser.PropertyChanging -= User_PropertyChanging;
					}
				}
				catch(Exception ex)
				{
					Console.WriteLine(ex);
				}
				finally
				{
					_originUser = SelectedItem;
					IsCanSelectionChanged = true;
				}
			});

			DeleteCmd ??= new RelayCommand(o => true, o =>
			{
				var user = o as User;
				if(user == null)
				{
					return;
				}

				Datas.Remove(user);
				UserEntity entity = ClassHelper.AutoMap<UserEntity, User>(user);
				_dbHelper.Delete(new List<UserEntity> { entity });
				ShowInfoUc($"已删除用户[{user.UserName}]");
				EditType = EditTypeEnum.Show;
			});

			EnterEditCmd ??= new RelayCommand(o => true, o =>
			{
				EditType = EditTypeEnum.Edit;
				if(SelectedItem != null)
				{
					SelectedItem.EditType = EditType;

					//演示属性变动后的业务处理(附加方法);
					SelectedItem.PropertyChanged += User_PropertyChanged;
					SelectedItem.PropertyChanging += User_PropertyChanging;
				}
			});

			LostFocusCmd ??= new RelayCommand(o => true, o =>
			{
				var args = o as RoutedEventArgs;

				if(args.Source.GetType() == typeof(DataGrid) && SelectedItem != null)
				{
					//SelectedItem.EditType = EditTypeEnum.Show;
				}
			});
		}

		#region 属性变动处理

		/// <summary>
		/// 属性变更中（记录原始值）
		/// </summary>
		private void User_PropertyChanging(object sender, PropertyChangingEventArgs e)
		{
			Type type = sender.GetType();
			PropertyInfo propertyInfo = type.GetProperty(e.PropertyName);
			if(propertyInfo != null)
			{
				_originPropertyValueDict[e.PropertyName] = propertyInfo.GetValue(sender);
			}
		}

		/// <summary>
		/// 原始的属性值字典
		/// </summary>
		private Dictionary<string, object> _originPropertyValueDict = new Dictionary<string, object>();

		/// <summary>
		/// 正在被还原的属性名列表
		/// </summary>
		private List<string> _revertPropertyList = new List<string>();

		/// <summary>
		/// 属性变更后（业务处理）
		/// </summary>
		private void User_PropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			try
			{
				//如果属性存在于忽略列表中，则从忽略列表中移除，并跳过此次执行（业务处理）
				if(_revertPropertyList.Contains(e.PropertyName))
				{
					_revertPropertyList.Remove(e.PropertyName);
					return;
				}

				bool isSuccess = true; //业务处理是否成功;
				var defaultObject = default(User); //只是用于获取属性名称;

				try
				{
					//业务处理;
					switch(e.PropertyName)
					{
						case nameof(defaultObject.UserName):
						{
							ToastToScreenCmd.Execute($"用户名设置成功：{SelectedItem.UserName}"); //模拟业务处理;
							break;
						}
						case nameof(defaultObject.Age):
						{
							//模拟还原属性原始值;
							if(SelectedItem.Age > 200)
							{
								isSuccess = false;
								ToastToScreenCmd.Execute("人不可能这么大年龄，请重新设置!");
							}
							break;
						}
						default:
						{
							//isSuccess = false;
							//ToastToScreenCmd.Execute("无对应项");
							break;
						}
					}
				}
				catch(Exception ex)
				{
					isSuccess = false;
					Console.WriteLine($"异常：{ex}");
				}

				if(isSuccess)
				{
					ToastToScreenCmd.Execute("设置完成");
				}
				else //不成功则还原值
				{
					//添加到忽略列表，避免循环;
					_revertPropertyList.Add(e.PropertyName);

					//还原原始值
					Type type = sender.GetType();
					PropertyInfo propertyInfo = type.GetProperty(e.PropertyName);
					if(propertyInfo != null)
					{
						propertyInfo.SetValue(sender, _originPropertyValueDict[e.PropertyName], null);
					}
				}
			}
			catch(Exception ex)
			{
				Console.WriteLine($"异常：{ex}");
			}
		}

		#endregion
	}
}
